package com.example.weblending.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.weblending.domain.File;
import com.example.weblending.domain.FileResult;
import com.example.weblending.domain.User;
import com.example.weblending.domain.statistics.StatisticsField;
import com.example.weblending.exception.GlobalException;
import com.example.weblending.mapper.FileMapper;
import com.example.weblending.mapper.FileResultMapper;
import com.example.weblending.mapper.UserMapper;
import com.example.weblending.service.AnalyzeService;
import com.example.weblending.service.RemoteService;
import com.example.weblending.service.TaskService;
import com.example.weblending.utils.StatisticsUtils;
import com.example.weblending.vo.AnalyzeColumn;
import com.example.weblending.vo.ResultFullColumn;
import feign.Feign;
import feign.Request;
import feign.jackson.JacksonEncoder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;

/**
 *
 */
@Service
public class AnalyzeServiceImpl implements AnalyzeService {
    @Resource
    private FileResultMapper fileResultMapper;
    @Resource
    private FileMapper fileMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private TaskService taskService;

    /**
     * 获得分析结果，只获得列表的第一条数据的分析结果，如果列表为空则获得默认的第0条的数据
     */
    @Override
    public FileResult getResult(Page<File> files) {
        List<File> list=files.getRecords();
        List<JSONObject> ids=new ArrayList<>();
        if(list.size()!=0){
            //只用文件列表的第一条数据获得分析结果
           File file=list.get(0);
           FileResult one=fileResultMapper.selectById(file.getFid());
           return one;
        }else{
            //文件列表为空则获得默认的第0条数据
            FileResult result=fileResultMapper.selectById(0);
           return result;
        }
    }

    /**
     * 清洗任务，为异步任务，
     * 结束后将任务类置为完成，file类取消绑定任务
     */
    @Async
    @Override
    public void clean(File file, User user) {
        this.clean(file);
        //用户清洗次数-1
        userMapper.updateById(user);
        //完成任务
        taskService.finishCleanTask(file);
        //解绑任务
        file.setTask(0);
        fileMapper.updateById(file);
    }


    /**
     * 分析任务，为异步任务，
     * 结束后将任务类置为完成，file类取消绑定任务，创建或保存分析结果
     */
    @Async
    @Override
    public void analyze(File file, User user) {
        FileResult result=this.AnalyzeCsv(file);
        result.setId(file.getFid());
        file.setOperateTime(new Timestamp(System.currentTimeMillis()));
        file.setStatus(2);

        if(fileResultMapper.selectById(file.getFid())!=null){
            fileResultMapper.updateById(result);
        }else{
            fileResultMapper.insert(result);
        }
        userMapper.updateById(user);
        taskService.finishAnalyzeTask(file);
        file.setTask(0);
        fileMapper.updateById(file);
        System.out.println("分析完成");
    }

    /**
     * 检查当前文件是否可以分析
     */
    @Override
    public void analyzeCheck(File file, User user) {
        int num=user.getAnalyzenum()-1;
        user.setAnalyzenum(num);
        if (num==-1){
            throw new GlobalException(40001,"您的账户分析次数已用尽，请联系管理员");
        }
        if(file.getTask()!=null&&file.getTask()!=0){
            throw new GlobalException(40000,"当前分析任务正在执行，请耐心等待");
        }
        if(file.getStatus()==0){
            throw new GlobalException(400,"请先清洗文件");
        }
    }

    /**
     * 检查当前文件是否可以清洗
     */
    @Override
    public void cleanCheck(File file, User user) {
        int num=user.getCleannum()-1;
        user.setCleannum(num);
        if (num==-1){
            throw new GlobalException(40001,"您的账户清洗次数已用尽，请联系管理员");
        }
        if(file.getTask()!=null&&file.getTask()!=0){
            throw new GlobalException(40000,"当前清洗任务正在执行，请耐心等待");
        }
        if(file.getStatus()!=0){
            throw new GlobalException(400,"当前文件无需清洗");
        }
    }

    @Override
    public FileResult getById(int id) {
        return fileResultMapper.selectById(id);
    }

    /**
     * 具体的清洗文件 方法
     * 构造Feign客户端来向python请求清洗
     * 完成后替换路径获得清洗后文件路径和分析结果文件路径
     */
    private void clean(File file){
        String path = file.getPath();
        //基于json
        RemoteService service = Feign.builder()
                .options(new Request.Options(100000, 350000))//设置超时时间
                //.retryer(new Retryer.Default(5000, 5000, 3)
                .target(RemoteService.class,   //代理对象
                        "http://localhost:8000/"); //目标地址
        try{
            //获得分析后结果文件路径
            String analyzePath =service.getFile(path);
            //获得清洗文件路径
            String washPath =analyzePath.replace("/resultfinal/","/wash/");
            //更新文件类
            file.setCleanpath(washPath);
            file.setFinishpath(analyzePath);
            file.setCleanTime(new Timestamp(System.currentTimeMillis()));
            file.setStatus(1);
        }
        catch (Exception e){
            throw new GlobalException(401,"上传文件格式错误，请重新上传");
        }

    }

    /**
     * 具体的分析文件
     * 构造Feign客户端来向python请求分析 相关性
     * 完成后替换路径获得清洗后文件路径和分析结果文件路径
     */
    private FileResult AnalyzeCsv(File file){
        FileResult fileResult=new FileResult();
        RemoteService service = Feign.builder()
                .options(new Request.Options(100000, 350000))//设置超时时间
                .target(RemoteService.class,   //代理对象
                        "http://localhost:8000/"); //目标地址
        String json="";
        try{
            //获得到条件相关性
             json=service.getJson(file.getFinishpath());
        }catch (Exception e){
            throw new GlobalException(500,"获得关联性数据失败");
        }
        //统计工具类
        StatisticsUtils statisticsUtils=new StatisticsUtils();
        //遍历分析结果文件来获得统计信息
        java.io.File clean=new java.io.File(file.getFinishpath());
        EasyExcel.read(clean, AnalyzeColumn.class, new PageReadListener<AnalyzeColumn>(dataList -> {
            for (AnalyzeColumn column : dataList) {
                statisticsUtils.statistics(column);
            }
        })).excelType(ExcelTypeEnum.CSV).sheet().doRead();
        //获得各个条件自己的成功率趋势
        fileResult.setFieldStatistic(statisticsUtils.result());
        //设置相关性
        fileResult.setRelevance(json);
        //各个条件按位编码后的中间统计结果，方便后面按照指定各个条件过滤
        fileResult.setFullStatistic(statisticsUtils.getConditionStatistic());
        //根据上面的按位编码的map 计算成功率并排序，取最大的前三个和最小的一个
        fileResult.setSortStatistic(statisticsUtils.sortResult(json));
        return fileResult;
    }
}




